package com.toprs.business.service

import cn.afterturn.easypoi.excel.ExcelExportUtil
import cn.afterturn.easypoi.excel.entity.TemplateExportParams
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.github.pagehelper.PageHelper
import com.toprs.base.config.GlobalCurrent
import com.toprs.base.config.RequestHolder
import com.toprs.base.entity.Dept
import com.toprs.base.entity.DeptManager
import com.toprs.base.entity.User
import com.toprs.base.entity.UserDept
import com.toprs.base.exception.CustomException
import com.toprs.base.mapper.*
import com.toprs.base.result.PageResult
import com.toprs.base.service.UserService
import com.toprs.business.entity.ApplicationBase
import com.toprs.business.entity.Step
import com.toprs.business.mapper.*
import com.toprs.business.query.AppQuery
import com.toprs.business.vo.AppApproveInfo
import com.toprs.business.vo.AppBackInfo
import jakarta.servlet.http.HttpServletResponse
import net.lingala.zip4j.ZipFile
import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.ClassPathResource
import org.springframework.stereotype.Service
import org.springframework.util.ResourceUtils
import org.springframework.web.multipart.MultipartFile
import java.io.*
import java.math.BigDecimal
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.*


@Service
class ApplicationService(
    val appMapper: ApplicationBaseMapper,
    val stepMapper: StepMapper,
    val deptManagerMapper: DeptManagerMapper,
    val userMapper: UserMapper,
    val deptMapper: DeptMapper,
    val userDeptMapper: UserDeptMapper
) {

    private val lastUserId = "1732245041696295"
    private val lastUserLId = "01344408093126195446"
    private val formater = SimpleDateFormat("YYYYMMddHHmmss")

    private fun insertStep(application: ApplicationBase, userid: String) {
        val s = (application.stateId?.minus(1))
        val e = application.stateId?.toInt()
        val step = Step(null, s, e, userid, null, null, application.currentUser, application.id)
        stepMapper.insert(step)

    }

    private fun getDeptManager(deptId: Int): String {
        val s = deptManagerMapper.selectselectBydeptId(deptId) ?: throw CustomException("没有部门负责人")
        return s.userid!!
    }


    fun buildApplication(application: ApplicationBase) {

        val userId = RequestHolder.getUserId()
        val managerId = getDeptManager(application.deptId!!)

        application.serialNumber = "${formater.format(Date())}${application.deptId}"
        application.applicant = userId
        application.applyDate = Date()

        val user = userMapper.selectByPrimaryKey(userId) ?: throw CustomException("用户不存在！")

        if (user.boss == 1.toShort()) {
            application.stateId = 4
            application.currentUser = "-1"
        } else if (userId == managerId) {
            application.stateId = if (application.cast!! < BigDecimal(800.00)) 4 else 3
            application.currentUser = if (application.cast!! < BigDecimal(800.00)) "-1" else lastUserId
        } else {
            application.currentUser = managerId
            application.stateId = 2
        }


        val statement = appMapper.getGeneralInsert2(application)
        appMapper.generalInsert(statement)
        application.id = statement.parameters["id"] as Int
        insertStep(application, userId)

    }

    fun editApplication(application: ApplicationBase) {

        val appId = application.id ?: throw CustomException("id不能为空")
        val userId = RequestHolder.getUserId()

        val app = appMapper.selectByPrimaryKey(appId) ?: throw CustomException("申请不存在！")

        if (app.applicant != userId) {
            throw CustomException("只有申请人可以修改！")
        }

        appMapper.updateByPrimaryKey(application)


    }


    fun queryApplication(appQuery: AppQuery): PageResult<ApplicationBase> {

        val user = userMapper.selectByPrimaryKey(RequestHolder.getUserId()) ?: throw CustomException("用户不存在")

        appQuery.manager = deptManagerMapper.selectByUserId(appQuery.userid!!).isNotEmpty()
        appQuery.boss =
            (appQuery.userid == lastUserId || appQuery.userid == lastUserLId || user.boss?.equals(1.toShort()) ?: false)


        if (appQuery.type !in listOf(0, 1, 2, 3, 4)) {
            throw CustomException("参数错误！")
        }

        PageHelper.startPage<ApplicationBase>(appQuery.pageNo, appQuery.pageSize)
        val list = appMapper.queryApp(appQuery)
        return PageResult.processPage(list)
    }

    fun getBaseInfo(id: Int): ApplicationBase {
        val info = appMapper.selectByPrimaryKey(id) ?: throw CustomException("申请不存在或已被删除！")
        return info
    }


    fun backApp(appBackInfo: AppBackInfo) {
        val operator = RequestHolder.getUserId()
        val app = appMapper.selectByPrimaryKey(appBackInfo.appid) ?: throw CustomException("该申请不存在")

        if (!app.currentUser.equals(operator)) {
            throw CustomException("您不能操作该申请！")
        }

        val steps = stepMapper.selectByAppId(appBackInfo.appid)
        val filterList = steps.filter { it.operatorId.equals(appBackInfo.userid) }
        if (filterList.isEmpty()) {
            throw CustomException("不能回退给当前用户")
        }
        val toStep = filterList.last()

        val step = Step(
            null,
            app.stateId?.toInt(),
            toStep.startState,
            operator,
            null,
            appBackInfo.msg,
            toStep.operatorId,
            app.id
        )
        stepMapper.insert(step)

        appMapper.updateBackInfo(toStep.operatorId!!, toStep.startState!!, app.id!!)

    }

    fun approveApp(appApproveInfo: AppApproveInfo) {
        val operator = RequestHolder.getUserId()
        val app = appMapper.selectByPrimaryKey(appApproveInfo.appid) ?: throw CustomException("该申请不存在")
        if (!app.currentUser.equals(operator)) {
            throw CustomException("您不能操作该申请！")
        }
        val managerId = getDeptManager(app.deptId!!)

//        val step = stepMapper.selectLast2me(operator)


        val iStep = Step()
//        if (step == null) {
        if (operator == lastUserId) {
            app.stateId = 4
            app.currentUser = "-1"
        } else if (operator == managerId) {
            app.stateId = if (app.cast!! < BigDecimal(800.00)) 4 else 3
            app.currentUser = if (app.cast!! < BigDecimal(800.00)) "-1" else lastUserId
        } else {
            app.currentUser = managerId
            app.stateId = 2
        }
        iStep.startState = (app.stateId!! - 1)


        iStep.endState = app.stateId!!.toInt()
        iStep.nextId = app.currentUser
        iStep.remark = appApproveInfo.msg
        iStep.operatorId = operator
        iStep.appId = app.id

        stepMapper.insert(iStep)
        appMapper.updateBackInfo(app.currentUser!!, app.stateId!!.toInt(), app.id!!)

    }

    fun closeApp(id: Int) {

        appMapper.closeApp(id)


    }

    fun searchSerialNumber(serialNumber: String): List<JSONObject> {

        return appMapper.select {
            where {
                ApplicationBaseDynamicSqlSupport.serialNumber.isLike("%$serialNumber%")
            }
        }.map {
            val obj = JSONObject()
            obj["serialNumber"] = it.serialNumber
            obj["id"] = it.id
            obj
        }


    }

    private fun jsonStr2File(s: String, path: String): File {
        val f = File(path)
        f.appendText(s, Charsets.UTF_8)
        return f
    }


    val dataPath by lazy {
        GlobalCurrent.dataPath
    }

    private fun getAllUserStr(): String {
        val list = userMapper.select { }.map {

            it.deptIds = null
            return@map it

        }
        return JSONObject.toJSONString(list)
    }

    private fun getAllDeptStr(): String {
        val list = deptMapper.select { }.map {
            it.children = null
            it
        }
        val str = JSON.toJSONString(list)
        return str
    }


    fun exportData(appQuery: AppQuery, response: HttpServletResponse) {
        appQuery.pageNo = 1
        appQuery.pageSize = 999999
        appQuery.userid = lastUserId
        appQuery.type = 3
        appQuery.deptId = null
        val files = mutableListOf<File>()

        val list = this.queryApplication(appQuery).list
        val dir = "data${System.currentTimeMillis()}"

        val base = jsonStr2File(JSONObject.toJSONString(list), "$dataPath${dir}base.txt")
        files.add(base)

        val ids = list!!.map { it.id!! }
        val stepTxt = jsonStr2File(JSONObject.toJSONString(stepMapper.selectByAppIds(ids)), "$dataPath${dir}step.txt")
        files.add(stepTxt)

        val userTxt = jsonStr2File(getAllUserStr(), "$dataPath${dir}user.txt")
        files.add(userTxt)


        val deptTxt = jsonStr2File(getAllDeptStr(), "$dataPath${dir}dept.txt")
        files.add(deptTxt)

        val userDeptTxt = jsonStr2File(JSON.toJSONString(userDeptMapper.select { }), "$dataPath${dir}userDept0.txt")
        files.add(userDeptTxt)

        val deptManagerTxt =
            jsonStr2File(JSON.toJSONString(deptManagerMapper.select { }), "$dataPath${dir}deptManager.txt")
        files.add(deptManagerTxt)


        val name = "$dir.zip"
        ZipFile("$dataPath$name").addFiles(files)

//        response.reset()
        response.contentType = "application/octet-stream"
        response.characterEncoding = "UTF-8"
        response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(name, "UTF-8"))

        val bis = FileInputStream("$dataPath$name")

        val os = response.outputStream
        os.write(bis.readAllBytes())
        os.flush()
        os.close()
        bis.close()

        for (f in files) {
            f.delete()
        }

        File("$dataPath$name").delete()

    }

    private fun handelTexts(path: String) {
        var baseFile: File? = null
        var stepFile: File? = null
        var userFile: File? = null
        var deptFile: File? = null
        var userDeptFile: File? = null
        var deptManagerFile: File? = null

        for (file in File(path).listFiles()!!) {
            if (file.name.endsWith("base.txt")) {
                baseFile = file
            } else if (file.name.endsWith("step.txt")) {
                stepFile = file
            } else if (file.name.endsWith("user.txt")) {
                userFile = file
            } else if (file.name.endsWith("dept.txt")) {
                deptFile = file
            } else if (file.name.endsWith("userDept0.txt")) {
                userDeptFile = file
            } else if (file.name.endsWith("deptManager.txt")) {
                deptManagerFile = file
            }
        }

        if (baseFile == null || stepFile == null || userFile == null || deptFile == null || userDeptFile == null || deptManagerFile == null) {
            throw CustomException("文件缺失")
        }


        // 处理部门

        var dept_txt = JSON.parseArray(deptFile.readText(Charsets.UTF_8), Dept::class.java)
        val exitsIds = deptMapper.select { }.map { it.id }
        dept_txt = dept_txt.filter { !exitsIds.contains(it.id) }
        if (dept_txt.isNotEmpty()) deptMapper.insertMultiple(dept_txt)

        // 处理用户
        var user_txt = JSON.parseArray(userFile.readText(Charsets.UTF_8), User::class.java)
        val exitsUserIds = userMapper.select { }.map { it.userid }
        user_txt = user_txt.filter { !exitsUserIds.contains(it.userid) }
        if (user_txt.isNotEmpty()) userMapper.insertMultiple(user_txt)

        //user dept
        val user_dept_txt = JSON.parseArray(userDeptFile.readText(Charsets.UTF_8), UserDept::class.java)
        userDeptMapper.delete { }
        userDeptMapper.insertMultiple(user_dept_txt)

        //deptManager
        val dept_manager_txt = JSON.parseArray(deptManagerFile.readText(Charsets.UTF_8), DeptManager::class.java)
        deptManagerMapper.delete { }
        deptManagerMapper.insertMultiple(dept_manager_txt)


        var apps_txt = JSON.parseArray(baseFile.readText(Charsets.UTF_8), ApplicationBase::class.java)


        //获取已经有的申请单的id
        val txtids = apps_txt.map { it.id!! }
        val existIds = appMapper.selectByIds(txtids).map { it.id!! }

        //排除已经存在的app
        apps_txt = apps_txt.filter { !existIds.contains(it.id!!) }

        if (apps_txt.isNotEmpty()) appMapper.insertMultiple(apps_txt)

        var step_txt = JSON.parseArray(stepFile.readText(Charsets.UTF_8), Step::class.java)
        //排除已经存在的step
        step_txt = step_txt.filter { !existIds.contains(it.appId) }
        if (step_txt.isNotEmpty()) stepMapper.insertMultiple(step_txt)
    }

    fun importData(file: MultipartFile?) {
        if (file == null) throw CustomException("文件不能为空！")

        val now = System.currentTimeMillis()
        val name = "${now}.zip"
        val ePath = "$dataPath$now"
        File(ePath).mkdir()

        try {
            val f = File("$dataPath$name")
            file.transferTo(f)
            val zipF = ZipFile("$dataPath$name")
            zipF.extractAll(ePath)
            f.delete()
            handelTexts(ePath)
        } catch (ex: IOException) {
            throw CustomException("上传失败：${ex.message}")
        }
    }

    private val timeFormat = SimpleDateFormat("YYYY-MM-dd HH:mm:ss")
    private val dateFormat = SimpleDateFormat("YYYY-MM-dd")
    private val wineType = listOf("定制", "青龙", "啤酒", "其他")


    fun exportExcelByIds(ids: List<Int>, response: HttpServletResponse) {

        val list = appMapper.selectByIdsWithName(ids)

        exportExcelImp(list, response)
    }

    private fun exportExcelImp(list: List<ApplicationBase>, response: HttpServletResponse) {

        val jsonList = JSON.parseObject(JSONObject.toJSONString(list), List::class.java) as List<JSONObject>

        for (json in jsonList) {
            json["applyDate"] = dateFormat.format(json["applyDate"])
            json["createTime"] = timeFormat.format(json["createTime"])
            json["useTime"] = timeFormat.format(json["useTime"])
            json["updateTime"] = if (json["updateTime"] != null) timeFormat.format(json["updateTime"]) else ""
            json["wineReport"] = if (json["wineReport"] == 0) "否" else "是"
            json["wineType"] = if (json["wineType"] == null) "" else wineType[json["wineType"] as Int]
        }


        val inputStream = ClassPathResource("template.xlsx").inputStream
        val params = TemplateExportParams(inputStream)
        val map: MutableMap<String, Any> = HashMap()

        map["maplist"] = jsonList
        map["title"] = "title"
        val workbook = ExcelExportUtil.exportExcel(params, map)

        response.contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        response.characterEncoding = "UTF-8"
        val os = response.outputStream
        workbook.write(os)
        os.flush()
        os.close()
    }

    fun exportExcel(appQuery: AppQuery, response: HttpServletResponse) {

        appQuery.pageNo = 1
        appQuery.pageSize = 999999
        appQuery.userid = RequestHolder.getUserId()
        appQuery.type = 3
        val list = this.queryApplication(appQuery).list
        exportExcelImp(list!!, response)


    }


}
